package source.control;

import java.util.Vector;

import source.Enums.Direction;
import source.Enums.Side;
import source.RobotControl;
import source.RobotControl.ExecutionState;
import source.calcCmd.RealLifeProperties;
import source.calcCmd.RobotCommand;
import source.control.Command;
import source.control.Serial;
import source.control.TableModel;
import source.control.Master;


public class CmdInterface {
	
	// Rows of the command database
	private Vector<RobotCommand> rows;
	
	// Table model for the command database
	private TableModel tableModel;
	private Master master;
	private Serial port;
	private Thread thread;
	
	private RobotControl robotControl;

	private int prevSpL, prevSpR;
	private double prevVL, prevVR;

	private ExecutionState execState;
	
	// running variable enables and disables giving commands to the uC
	private volatile boolean running;
	// working variable is a flag showing whether we have a thread already
	private volatile boolean working;

	public int getPrevSp(Side s){
		switch (s) {
		case LEFT:
			return prevSpL;
		case RIGHT:
			return prevSpR;
		}
		
		return 0;
	}
	
	public double getPrevV(Side s){
		switch (s) {
		case LEFT:
			return prevVL;
		case RIGHT:
			return prevVR;
		}
		
		return 0;
	}
	
	public void setPrevV(Side s, double val){
		switch (s) {
		case LEFT:
			prevVL = val;
			break;
		case RIGHT:
			prevVR = val;
			break;
		}
	}
	
	public void setPrevSp(Side s, int val){
		switch (s) {
		case LEFT:
			prevSpL = val;
			break;
		case RIGHT:
			prevSpR = val;
			break;
		}

	}
	
	private static void initCommands(){
		
	
	}
	
	public Serial getPort(){
		return port;		
	}
	
	// getting the number of waiting commands
	// Number Of Commands
	public int noCommands(){
		return rows.size();
	}
	
	// function to call when a thread is done working
	public void done(){
		setWorking(false);
		if (prevSpL != 255 || prevSpR != 255){
			Direction dirL = (prevVL < 0 ? Direction.BACKWARD : Direction.FORWARD);
			Direction dirR = (prevVR < 0 ? Direction.BACKWARD : Direction.FORWARD);
			addCommand(RobotCommand.toZero(prevSpL, prevSpR, dirL, dirR));
			
			startRunning();
			
			setPrevSp(Side.LEFT, RealLifeProperties.timerMaxValue);
			setPrevSp(Side.RIGHT, RealLifeProperties.timerMaxValue);
			
			setPrevV(Side.LEFT,0);
			setPrevV(Side.RIGHT,0);
		} else {
			execState = ExecutionState.ready;
		}
	}
	
	// reading the next command
	public RobotCommand readRow(){
		
		if (rows.size() == 0) return null;
		RobotCommand ret = rows.elementAt(0); 
		rows.remove(0);
		tableModel.fireTableRowsDeleted(0, rows.size());
		return ret;
	}
	
	public ExecutionState getExecState(){
		return execState;
	}
	public void addCommand(RobotCommand cmd){
		rows.add(cmd);
		prevSpL = cmd.getSpeedL();
		prevSpR = cmd.getSpeedR();
		tableModel.fireTableRowsInserted(0, rows.size());
	}
	
	public void stopRunning(){
		port.write("stop");
		
		//port.write("reset");
		setRunning(false);

		setPrevSp(Side.LEFT, RealLifeProperties.timerMaxValue);
		setPrevSp(Side.RIGHT, RealLifeProperties.timerMaxValue);
		
		setPrevV(Side.LEFT,0);
		setPrevV(Side.RIGHT,0);
		
		execState = ExecutionState.ready;
		
		port.write("ping");
	}
	
	public void startRunning(){
		
		thread = new Thread(master);
		setRunning(true);
		if (!isWorking())(thread).start();
		
		execState = ExecutionState.running;
			
	}
	
	public void reset(){
		port.write("reset");
		setRunning(false);
		port.write("ping");
	}
	
	public boolean isRunning() {
		return running;
	}

	public void setRunning(boolean running) {
		this.running = running;
	}

	public boolean isWorking() {
		return working;
	}

	public void setWorking(boolean working) {
		this.working = working;
	}
	
	/**
	 * Create the frame.
	 */
	public CmdInterface(Serial port, RobotControl rc) {
		prevSpL = 255;
		prevSpR = 255;
		
		prevVL = 0;
		prevVR = 0;
		
		setRunning(false);
		setWorking(false);
		
		master = new Master(this);
		// initializing table rows
		rows = new Vector<RobotCommand>();
		//initializing talbe model
		tableModel = new TableModel(rows);
		
		robotControl = rc;
		
		this.port = port;
		
		execState = ExecutionState.ready;
	}
	
	
}
